// 
// SoapTrace.Net - A soap message monitoring utility. 
// 
// Copyright (C) 2004 Matthew Ward
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// Matthew Ward (mrward@users.sourceforge.net)
// 

using ICSharpCode.SharpZipLib;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using System;
using System.Globalization;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;

namespace SoapTrace.Core.Formatters
{
	/// <summary>
	/// <para>Object that formats strings based on the type.  This formatter
	/// is used to format <see cref="WebServiceParameter"/> objects and
	/// <see cref="WebServiceReturnValue"/> objects.</para>
	/// </summary>
	/// <remarks><para>Supported types are:</para>
	/// <para>xml</para>
	/// <para>compressedXml</para>
	/// </remarks>
	public sealed class ValueFormatter
	{
		/// <summary>
		/// Private constructor since this is a utility class.
		/// </summary>
		private ValueFormatter( )
		{
		}

		/// <summary>
		/// Formats a string value based on the specified type.
		/// </summary>
		/// <param name="valueType">The type of the string.</param>
		/// <param name="valueText">The value to format.</param>
		/// <returns>A formatted string.</returns>
		public static string Format( string valueType, string valueText )
		{
			string Text = String.Empty; 

			try
			{
				if( String.Compare( valueType, "xml", true, CultureInfo.InvariantCulture ) == 0 )
				{
					Text = String.Concat( "\r\n", 
						IndentedFormat( valueText ),
						"\r\n" );
				}
				else if( String.Compare( valueType, "compressedxml", true, CultureInfo.InvariantCulture ) == 0 )
				{
					valueText = Uncompress( valueText );
					Text = String.Concat( "\r\n", 
						IndentedFormat( valueText ),
						"\r\n" );
				}
				else
				{
					Text = valueText;
				}
			}
			catch( XmlException Ex )
			{
				// Must be non-xml text, just pass back the unformatted string instead.

				Debug.WriteLine( String.Concat( "ValueFormatter::Format Using plain text. ",
					Ex.Message ) );
				Text = valueText;
			}

			return Text;

		}

		/// <summary>
		/// Pretty print version of xml.
		/// </summary>
		/// <param name="xml">The xml to format.</param>
		/// <returns>A pretty print version of the xml.</returns>
		public static string IndentedFormat( string xml )
		{
			string IdentedXml = xml;
			
			XmlTextReader Reader = new XmlTextReader( new StringReader( xml ) );
			Reader.WhitespaceHandling = WhitespaceHandling.None;

			StringWriter IdentedXmlWriter = new StringWriter( CultureInfo.InvariantCulture );
			XmlTextWriter Writer = new XmlTextWriter( IdentedXmlWriter );
			Writer.Indentation = 1;
			Writer.IndentChar = '\t';
			Writer.Formatting = Formatting.Indented;
			Writer.WriteNode( Reader, false );
			Writer.Flush( );

			IdentedXml = IdentedXmlWriter.ToString( );
			
			return IdentedXml;
		}

		/// <summary>
		/// Uncompresses a gzipped and then base 64 encoded string.
		/// </summary>
		/// <param name="text">The gzipped/base 64 encoded string.</param>
		/// <returns>A uncompressed plain text string.</returns>
		public static string Uncompress( string text )
		{
			StringBuilder UncompressedText = new StringBuilder( );
			
			try
			{
				byte[ ] InputBytes = Convert.FromBase64String( text );
	
				Inflater Inflater = new Inflater( true );
	
				byte[ ] OutputBytes = new byte[ 1024 ];
	
				Inflater.SetInput( InputBytes );
	
				do
				{
					int BytesUncompressed = Inflater.Inflate( OutputBytes );
	
					if( BytesUncompressed == 0 )
					{
						if( Inflater.IsFinished == false )
						{
							throw new ApplicationException( "Unable to compress bytes." );
						}
					}
					else
					{
						UncompressedText.Append( 
							UnicodeEncoding.Unicode.GetString( OutputBytes, 0, BytesUncompressed ) );
					}
				}
				while( Inflater.IsFinished == false );
			}
			catch( ApplicationException Ex )
			{
				// Not base 64 encoded.
				
				Debug.WriteLine( String.Concat( "ValueFormatter::Uncompress.  Text='", text, "'.", 
					Ex.Message ) );
				
				UncompressedText.Append( text );
			}

			return UncompressedText.ToString( );
		}

	}
}
